// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2025-04-02

package table

type (
	// Body
	// 表体.
	Body interface {
		Add(rows ...Row) Body
		GetRow(index int) Row
		GetRows() []Row
		GetWidth(index int) (width int)
		GetWidths() map[int]int
		Iterate(fn BodyIterator) Body
	}

	// BodyIterator
	// 表体遍历.
	BodyIterator func(index int, row Row)

	body struct {
		length int
		width  map[int]int
		rows   []Row
	}
)

// NewBody
// 创建表体.
func NewBody() Body {
	return &body{
		width: make(map[int]int),
		rows:  make([]Row, 0),
	}
}

// +---------------------------------------------------------------------------+
// | Interface methods                                                         |
// +---------------------------------------------------------------------------+

func (o *body) Add(rows ...Row) Body {
	o.rows = append(o.rows, rows...)
	o.length = len(o.rows)

	for _, r := range o.rows {
		for k, v := range r.GetWidths() {
			if n, ok := o.width[k]; ok {
				if v > n {
					o.width[k] = v
				}
			} else if o.width[k] < v {
				o.width[k] = v
			}
		}
	}
	return o
}

func (o *body) GetWidth(index int) (width int) {
	if v, ok := o.width[index]; ok {
		width = v
	}
	return
}

func (o *body) GetWidths() map[int]int { return o.width }

func (o *body) GetRow(index int) Row {
	if index >= 0 && index < o.length {
		return o.rows[index]
	}
	return nil
}

func (o *body) GetRows() []Row { return o.rows }

func (o *body) Iterate(fn BodyIterator) Body {
	for i, r := range o.rows {
		fn(i, r)
	}
	return o
}
